package com.nd.fastdp.file.controller;

import cn.hutool.core.lang.UUID;
import com.nd.fastdp.file.constant.ErrorCodeEnum;
import com.nd.fastdp.file.convert.FileConvert;
import com.nd.fastdp.file.model.bo.FileBO;
import com.nd.fastdp.file.model.dto.FileAddParam;
import com.nd.fastdp.file.model.dto.FileModifyBusIdParam;
import com.nd.fastdp.file.model.entity.NdFile;
import com.nd.fastdp.file.service.FileService;
import com.nd.fastdp.file.vo.FileVO;
import com.nd.fastdp.framework.pojo.constant.DelStatusEnum;
import com.nd.fastdp.framework.pojo.dto.StateParam;
import com.nd.fastdp.framework.pojo.vo.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;

/**
 * @Auther: 刘畅
 * @Date: 2019-03-08 21:11
 * @Description:
 */
@CrossOrigin
@RestController
@RequestMapping("/file")
@Api(tags = {"文件管理"})
public class FileController {

    @Value("${fastdp.domainName}")
    private String domainName;

    @Autowired
    private FileService fileService;

    @PostMapping("/upload")
    @ApiOperation(value = "上传")
    @ApiParam(name="file", value = "上传的文件", required = true)
    public Result upload(@RequestParam("file") MultipartFile file) throws IOException {

        FileAddParam param = new FileAddParam();
        param.setFile(file.getBytes());
        param.setOriginalFilename(file.getOriginalFilename());

        FileBO bo = fileService.add(param);
        FileVO vo = FileConvert.INSTANCE.to(bo);

        return Result.OK(vo);
    }

    @PostMapping("/noBindUpload")
    @ApiOperation(value = "无业务绑定上传")
    @ApiParam(name="file", value = "上传的文件", required = true)
    public Result uploadX(@RequestParam("file") MultipartFile file) throws IOException {

        FileAddParam param = new FileAddParam();
        param.setFile(file.getBytes());
        param.setOriginalFilename(file.getOriginalFilename());

        FileBO bo = fileService.add(param);
        FileVO vo = FileConvert.INSTANCE.to(bo);

        fileService.updateBusId(bo.getId(), UUID.randomUUID().toString(), NdFile.DEFAULT_TYPE);

        return Result.OK(vo);
    }

    /**
     * 根据
     */
    @PostMapping("/bind")
    @ApiOperation(value = "绑定")
    public Result bindBusId(@RequestBody FileModifyBusIdParam param) {

        fileService.updateBusId(param.getIds(), param.getBusId(), param.getBusType());

        return Result.OK();
    }

    @PostMapping("/del")
    @ApiOperation(value = "删除")
    @ApiParam(name="ids", value = "删除的文件ID", required= true, example = "[ids]")
    public Result del(@RequestBody List<String> ids) {

        StateParam param = new StateParam();
        param.setIds(ids).setState(DelStatusEnum.DEL.getValue());

        fileService.updateState(param);

        return Result.OK();
    }

    /**
     * 根据id 返回文件流
     *
     * @param id
     * @param response
     * @throws IOException
     */
    @GetMapping("/download/{id}")
    @ApiOperation(value = "下载")
    @ApiParam(name="id", value = "文件ID", required= true)
    public void file(@PathVariable("id") String id, HttpServletResponse response) throws IOException {

        FileBO file = fileService.get(id);

        writeFile(file, false, response);
    }

    /**
     * 根据id 返回文件流
     *
     * @param id
     * @param response
     * @throws IOException
     */
    @GetMapping("/preView/{id}")
    @ApiOperation(value = "预览")
    @ApiParam(name="id", value = "文件ID", required= true)
    public void preView(@PathVariable("id") String id, HttpServletResponse response) throws IOException {

        FileBO file = fileService.get(id);

        writeFile(file, true, response);
    }

    /**
     * 根据id 返回附件详情信息
     *
     * @param id
     */
    @GetMapping("/get/{id}")
    @ApiOperation(value = "详情")
    @ApiParam(name="id", value = "文件ID", required= true)
    public Result get(@PathVariable("id") String id) {

        FileBO bo = fileService.get(id);
        FileVO vo = FileConvert.INSTANCE.to(bo);

        return Result.OK(vo);
    }

    /**
     * 直接返回流
     *
     * @param busId
     * @param busType
     * @param response
     * @throws IOException
     */
    @GetMapping("/downloadByBusIdAndBusType")
    @ApiOperation(value = "单一文件根据业务ID和类型下载")
    public void file(@ApiParam(name="busId", value = "业务ID", required= true) @RequestParam(name = "busId") String busId,
                     @ApiParam(name="busType", value = "业务类型", required= true) @RequestParam(name = "busType") String busType,
                     HttpServletResponse response) throws IOException {

        List<FileBO> appendixFiles = fileService.findByTypeAndBusId(busType, busId);

        if (appendixFiles == null || appendixFiles.isEmpty()) {
            response.setContentType("text/html;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");
            response.getWriter().write(ErrorCodeEnum.SOURCE_NOT_EXIST_ERROR.getDesc());
            return;
        }

        FileBO fileBO = appendixFiles.get(0);

        writeFile(fileBO, false, response);
    }

    @ApiOperation(value = "清理无效文件")
    @GetMapping("/clearTemp")
    public Result clearTemp() {

        fileService.clearTemp();

        return Result.OK();
    }

    @ApiOperation(value = "根据业务类型和业务ID查询")
    @GetMapping("/findByTypeAndBusId")
    public Result findByTypeAndBusId(@ApiParam(name="busId", value = "业务ID", required= true) @RequestParam(name = "busId") String busId,
                                     @ApiParam(name="busType", value = "业务类型", required= true) @RequestParam(name = "busType") String busType) {

        List<FileBO> bo = fileService.findByTypeAndBusId(busType, busId);

        List<FileVO> vo = FileConvert.INSTANCE.to(bo);

        return Result.OK(vo);
    }

    /*
     * 写入文件
     * */
    private void writeFile(FileBO fileBO, Boolean isPreView, HttpServletResponse response) throws IOException {

        File file = fileService.file(fileBO.getId());

        if (file.exists()) {

            String originalName = fileBO.getOriginalName();
            String path = fileBO.getPath();
            if (isVideo(originalName)) {
                // nginx 前缀
                String filePath = domainName + "/downloadVideo" + path;
                response.sendRedirect(filePath);
                return;
            }

            if(!isPreView){

                response.setContentType("application/octet-stream");
                response.setHeader("content-busType", "application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileBO.getOriginalName(), "UTF-8"));

            }else{

                response.setContentType("application/pdf");
                response.setHeader("content-busType", "application/pdf");
            }

            byte[] buffer = new byte[1024];
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            try {
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                OutputStream os = response.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (bis != null) bis.close();
                if (fis != null) fis.close();
            }
        } else {
            response.setContentType("text/html;charset=UTF-8");
            response.setCharacterEncoding("UTF-8");

            response.getWriter().write(ErrorCodeEnum.SOURCE_NOT_EXIST_ERROR.getDesc());
        }

    }

    public boolean isVideo(String fileName) {
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));

        fileExtension = fileExtension.toLowerCase();
        if (".mp4".equals(fileExtension)) {
            return true;
        }
        if (".wmnv".equals(fileExtension)) {
            return true;
        }
        if (".rmvb".equals(fileExtension)) {
            return true;
        }
        if (".rm".equals(fileExtension)) {
            return true;
        }
        return false;
    }

}
